home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magnum One
/
Magnum One (Mid-American Digital) (Disc Manufacturing).iso
/
d18
/
tpa2_a.arc
/
MICROMTR.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1991-04-28
|
8KB
|
272 lines
Uses CRT;
{═══════════════════════════ MICROMTR.PAS ═══════════════════════════}
{ Usage: MicroMtr (From Editor, just Run) }
{═══════════════════════════ MICROMTR.PAS ═══════════════════════════}
{- This demonstration illustrates the use of Assemble in place of }
{- Inline to create (Assembly) Inline Directive/MACROs. The Macros }
{- StartMicroMeter and StopMicroMeter are used to examine code }
{- length and execution speed of the section of Pascal or Assembly }
{- code placed between them. Precision is sufficient to measure }
{- down to a single assembly language instruction, however be }
{- forewarned: the actual in-place execution speed will depend on a }
{- number of complicated factors, including Prefetch Queue status }
{- and Byte/Word alignment. For this reason, differences of 10 }
{- clock cycles (about 3 timer counts) should not be considered }
{- significant. For further explanation please see Byron Sheppard, }
{- "High-Performance Software Analysis on the IBM PC", BYTE Magazine }
{- January 1987, p157. }
{- StartMicroMeter and StopMicroMeter calls cannot be nested -}
{- MAKE SURE START AND STOP 'MACROS' ARE OF EVEN BYTE LENGTH -}
{- THEY SHOULD THEN GIVE AN ACCURATE COUNT FOR IN-PLACE CODE -}
{════════════════ Global Variables used by MicroMeter ═══════════════}
VAR
CodeOverHead : WORD;
AverageCount, CountOverHead,
AverageCycles,CycleOverHead : LongInt;
LoopLoc, Count, Counter, TimerSumLo, TimerSumHi, CodeCount : WORD;
TimerSum: LongInt Absolute TimerSumLo;
{═════════════════════════ StartMicroMeter ══════════════════════════}
{ MACRO to start timer and REPEATEDly execute subsequent code. Use }
{ MicroMeterInit(1) to examine sections of a working program. }
{═════════════════════════ StartMicroMeter ══════════════════════════}
PROCEDURE StartMicroMeter;
ASSEMBLE {- Assembly Inline Directive -}
; Start Code
Nop ; Pad to even byte length
Mov Ax,Count
Mov Counter,Ax
Xor Ax,Ax
Mov TimerSumLo,Ax
Mov TimerSumHi,Ax
Jmp Short PushLoopLC
PopLoopLoc:
Pop LoopLoc
Jmp Short TimerLoop
PushLoopLC:
Call PopLoopLoc
TimerLoop:
;- Initialize timer, counter 0
Mov Al,$34 ;counter 0, LSB then MSB, mode 2, binary
Out $43,Al ;mode register
Xor Ax,Ax
Out $40,Al ;Set LSB
Out $40,Al ;Then MSB
END Assemble; {- StartMicroMeter -}
{══════════════════════════ StopMicroMeter ══════════════════════════}
{ MACRO to stop timer and REPEATEDly loop back to last Start. Use }
{ MicroMeterInit(1) to examine sections of a working program. }
{══════════════════════════ StopMicroMeter ══════════════════════════}
PROCEDURE StopMicroMeter;
ASSEMBLE {- Assembly Inline Directive -}
; Stop code
;- read timer, counter 0
Nop ;Pad to even byte length
Mov Al,0
Out $43,Al ;mode register
In Al,$40
Mov Dl,Al
In Al,$40
Mov Dh,Al ;Dx has 16 bit timer count
Neg Dx ; = $10000 - Dx
Add TimerSumLo,Dx
IF C Inc TimerSumHi
Dec Counter
IF NZ Jmp LoopLoc ;Indirect Jmp to Addr stored during StartMicroMeter
;Else Finished: Use 4*TimerSum/Count to estimate clock cycles
Call PopLocCounter
PopLocCounter:
Pop Ax
Sub Ax,LoopLoc
Sub Ax,CodeOverhead
Mov CodeCount,Ax
END Assemble; {- StopMicroMeter -}
{══════════════════════════ MicroMeterRead ══════════════════════════}
{ Read accumulated sums from last Start/StopMicroMeter loop. }
{══════════════════════════ MicroMeterRead ══════════════════════════}
PROCEDURE MicroMeterRead;
BEGIN
AverageCount := Round(TimerSum/Count - CountOverHead);
AverageCycles:= Round(4*TimerSum/Count - CycleOverHead);
WRITELN(CodeCount,' bytes code ',
'Count: ',AverageCount,' Cycles: ',AverageCycles);
END;
{════════════════════════════ ReadCount ═════════════════════════════}
{ Display String S, Code Length, and Average timer counts from last }
{ StartMicroMeter/StopMicroMeter loop. }
{════════════════════════════ ReadCount ═════════════════════════════}
PROCEDURE ReadCount(S:String);
BEGIN
AverageCount:= Round(TimerSum/Count - CountOverHead);
WRITELN(S,'':30-Length(S),CodeCount:5,' bytes code, Averages ',
AverageCount,' Timer Counts');
END;
{════════════════════════════ ReadCycles ════════════════════════════}
{ Display String S, Code Length, and Average clock cycles from last }
{ StartMicroMeter/StopMicroMeter loop. (assumes 4 cycles/count) }
{════════════════════════════ ReadCycles ════════════════════════════}
PROCEDURE ReadCycles(S:String);
BEGIN
AverageCycles:= Round(4*TimerSum/Count - CycleOverHead);
WRITELN(S,'':30-Length(S),CodeCount:5,' bytes code, Averages ',
AverageCycles,' Clock Cycles');
END;
{══════════════════════════ MicroMeterInit ══════════════════════════}
{ Initialize Global repetition Count and determine overhead due to }
{ StartMicroMeter and StopMicroMeter code }
{══════════════════════════ MicroMeterInit ══════════════════════════}
PROCEDURE MicroMeterInit(RepCount:WORD);
BEGIN
Count := RepCount; {- Set Global Variable -}
CodeOverHead := 0;
CountOverHead := 0;
CycleOverHead := 0;
StartMicroMeter;
StopMicroMeter;
Write('Initializing: ');
MicroMeterRead; {- Compute averages and display -}
CodeOverHead := CodeCount;
CountOverHead := AverageCount;
CycleOverHead := AverageCycles;
END; {PROCEDURE MicroMeterInit;}
{══════════════════════ Demonstrate MicroMeter ══════════════════════}
VAR
n,Dummy : INTEGER;
PROCEDURE MulTest;
BEGIN
WRITELN('Multiply tests:');
StartMicroMeter;
ASSEMBLE
mov dl,15
mul dl
End; {Assemble}
StopMicroMeter;
ReadCycles('Mul Instruction');
StartMicroMeter;
ASSEMBLE
mov dx,ax
mov cl,4
sal al,cl
sub ax,dx
End; {Assemble}
StopMicroMeter;
ReadCycles('Shift(Cl) and subtract');
StartMicroMeter;
ASSEMBLE
mov dx,ax
sal al,1
sal al,1
sal al,1
sal al,1
sub ax,dx
End; {Assemble}
StopMicroMeter;
ReadCycles('Repeated Shift(1) and subtract');
END; {PROCEDURE MulTest;}
PROCEDURE IncTest;
BEGIN
WRITELN('Increment tests:');
StartMicroMeter;
Dummy := Dummy + 1;
StopMicroMeter;
ReadCycles('Dummy := Dummy + 1;');
StartMicroMeter;
Dummy := Succ(Dummy);
StopMicroMeter;
ReadCycles('Dummy := Succ(Dummy);');
StartMicroMeter;
Inc(Dummy);
StopMicroMeter;
ReadCycles('Inc(Dummy);');
StartMicroMeter;
Inc(Dummy);
StopMicroMeter;
ReadCycles('Inc(Dummy);');
StartMicroMeter;
Asm Inc Dummy;
StopMicroMeter;
ReadCycles('asm Inc Dummy');
StartMicroMeter;
Asm Inc Dummy;
StopMicroMeter;
ReadCycles('asm Inc Dummy');
StartMicroMeter;
Inc(Dummy);
StopMicroMeter;
ReadCycles('Inc(Dummy);');
StartMicroMeter;
ASSEMBLE
Mov Ax,Dummy
Inc Ax
Mov Dummy,Ax
End;
StopMicroMeter;
ReadCycles('asm Inc Ax:Dummy');
END; {PROCEDURE IncTest;}
BEGIN
MicroMeterInit(1000);
StartMicroMeter;
Dummy := 0;
StopMicroMeter;
ReadCycles('Dummy := 0; ');
StartMicroMeter;
ASSEMBLE
Mov Dummy,0
End;
StopMicroMeter;
ReadCycles('Mov Dummy,0 ');
StartMicroMeter;
ASSEMBLE
Xor ax,ax
Mov Dummy,ax
End;
StopMicroMeter;
ReadCycles('Xor Ax,Ax | Mov Dummy,Ax ');
IncTest;
MulTest;
MicroMeterInit(100);
StartMicroMeter;
{- This is a MICROmeter - overflow beyond count 65535 is not detected -}
{- Experiment by increasing the loop limit below to cause overflow -}
FOR n := 1 TO 20 DO WRITE('Direct Video Write'#13);
StopMicroMeter;
ReadCycles('Direct Video Write');
MicroMeterRead;
END.